/*
 * @Author: zxc
 * @Date: 2020-08-05 08:27:54
 * @LastEditTime: 2020-08-06 15:03:34
 * @LastEditors: zxc
 * @Description: 高级类型
 */

// 交叉类型
// const mergeFunc = <T, U>(a: T, b: U): T & U => {
//   let res = {} as T & U;
//   res = Object.assign(a, b);
//   return res;
// };

// 联合类型
// const getLength = (content:string|number):number => {
//   if(typeof content ==='string') return content.length
//   else {return content.toString().length}
// }

// console.log(getLength(123))

// 类型保护 typeof
const valueList = [124, "abc"];
const getRandomValue = () => {
  // tslint:disable-next-line:variable-name
  const number = Math.random() * 10;
  if (number < 5) return valueList[0];
  else return valueList[1];
};
let itms = getRandomValue();
function isString(value: number | string): value is string {
  return typeof value === "string";
}
// if(isString(itms)){
//   console.log(itms.length)
// } else {
//   console.log(itms.toFixed())
// }

// 类型保护  instanceof
class CreatedByClass1 {
  public age = 18;
  // tslint:disable-next-line:no-empty
  constructor() {}
}
class CreatedByClass2 {
  public name = "zxc";
  // tslint:disable-next-line:no-empty
  constructor() {}
}
const getRandomClass = () => {
  return Math.random() < 0.5 ? new CreatedByClass1() : new CreatedByClass2();
};

// const itms1 = getRandomClass()
// if(itms1 instanceof CreatedByClass1){
//   console.log(itms1.age)
// } else {
//   console.log(itms1.name)
// }

// null/undefined
// let values = '123'

const sumFunc = (a: number, b?: number) => {
  return a + (b || 0);
};

// 类型保护、类型断言
const getLFunc = (a: string | null): number => {
  return (a || "").length;
};
function getSplitStr(a: number | null): string {
  function getRes(prefix: string) {
    return prefix + a!.toFixed().toString();
  }
  a = a || 0.1;
  return getRes("zxc-");
}
// console.log(getSplitStr(1.9))

// 类型别名（只可以在对象属性中引用类型别名自己）
type TypeString = string;
let str: TypeString;

type PostitionType<T> = {
  x: T;
  y: T;
};
const position1: PostitionType<number> = {
  x: 1,
  y: -1,
};
const position2: PostitionType<string> = {
  x: "a",
  y: "b",
};
type Childs<T> = {
  current: T;
  child?: Childs<T>;
};
let ccc: Childs<string> = {
  current: "first",
  child: {
    current: "sectond",
  },
};
// console.log(ccc)
// 当为接口起别名时，不可以使用extends和implements

type Alias = {
  num: number;
};
interface Interface {
  num: number;
}
let _alisa: Alias = {
  num: 23,
};
let _interface: Interface = {
  num: 32,
};
_alisa = _interface;

// 字面量
type Name = "zxc";
const nams: Name = "zxc";

type Direc = "a" | "b" | "c";
function getDirec(x: Direc) {
  return x;
}
// getDirec('d')  //error
getDirec("a");

type Age = 14;
interface InfoInterface {
  name: string;
  age: Age;
}
const _info: InfoInterface = {
  name: "aa",
  // age:20 //error
  age: 14,
};

// 可辨识联合/标签联合/代数 数据类型
/***
 * 1.具有普通的单例类型属性
 * 2. 一个类型别名包含了哪些地类型的联合
 */
interface Square {
  kind: "square";
  size: number;
}
interface Rectangle {
  kind: "rectangle";
  height: number;
  width: number;
}
interface Circle {
  kind: "circle";
  radius: number;
}

type Shape = Square | Rectangle | Circle;
const assertNever = (value: never): never => {
  throw new Error("Unexpected object：" + value);
};
function getArea(s: Shape): number {
  switch (s.kind) {
    case "square":
      return s.size * s.size;
      break;
    case "rectangle":
      return s.height * s.width;
      break;
    case "circle":
      return s.radius ** 2 * Math.PI;
      break;
    default:
      return assertNever(s);
  }
}

/**
 * @Author: zxc
 * @Date: 2020-08-06 08:47:22
 * @func: this
 */
class Counter {
  constructor(public count: number = 0) {}
  public add(value: number) {
    this.count += value;
    return this;
  }
  public sub(value: number) {
    this.count -= value;
    return this;
  }
}

class PowCounter extends Counter {
  constructor(public count: number = 0) {
    super(count);
  }
  pow(value: number) {
    this.count = this.count ** value;
    return this.count;
  }
}

let counters = new PowCounter(10);
// console.log(counters.sub(2).pow(2))

/**
 * @Author: zxc
 * @Date: 2020-08-06 08:54:50
 * @func: 索引类型
 */
// keyof
interface InfosIts {
  name: string;
  age: number;
}
let infoPs: keyof InfoInterface;
infoPs = "name";
infoPs = "age";
// infoPs = 'sex'

function getVas<T, K extends keyof T>(obj: T, name: K[]): T[K][] {
  return name.map((n) => obj[n]);
}
const objin = {
  name: "zxc",
  age: 23,
};
let valuess: (string | number)[] = getVas(objin, ["name", "age"]);
console.log(valuess);

// []索引访问操作符
type NameTypes = InfosIts["name"];
function getpro<T, K extends keyof T>(o: T, name: K): T[K] {
  return o[name];
}
interface Ojbs<T> {
  [key: string]: T;
}
let keys: keyof Ojbs<number>;

const ojbs: Ojbs<number> = {
  age: 18,
};
let keyss: Ojbs<number>["name"];

interface Type {
  a: never;
  b: never;
  c: string;
  d: number;
  e: undefined;
  f: null;
  g: object;
}
type Test = Type[keyof Type];

// 映射类型
interface Innfo {
  age: number;
  name: string;
  sex: string;
}
interface ReadOnlyInnfo {
  readonly age: number;
}

type ReadOnlyType<T> = {
  readonly [P in keyof T]?: T[P];
};

type ReadOnlyInnfo1 = ReadOnlyType<Innfo>;
let innfo1: ReadOnlyInnfo1 = {
  age: 18,
  name: "zxc",
  // sex:'man'
};
// innfo1.age = 23

// ReadOnly Partial
type ReadOnlyInnfo2 = Readonly<Partial<Innfo>>;

// Pick Record
interface Innfos {
  name: string;
  age: number;
  address: string;
}
const innfos2: Innfos = {
  name: "zxc",
  age: 28,
  address: "aaa",
};
// tslint:disable-next-line:no-shadowed-variable
function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
  const res: any = {};
  keys.map((e) => (res[e] = obj[e]));
  return res;
}
const nameAddress = pick(innfos2, ["address"]);
console.log(nameAddress);

// 场景：要将对象中的每一个属性的值进行转换
function mapObjs<K extends string | number, T, U>(
  obj: Record<K, T>,
  f: (x: T) => U
): Record<K, U> {
  const res: any = {};
  // tslint:disable-next-line:forin
  for (const key in obj) {
    res[key] = f(obj[key]);
  }
  return res;
}
const namess = { 1: "S", 2: "W", 3: "SDF" };
console.log(mapObjs(namess, (s) => s.length));

// 同态 两个相同类型的代数结构之间的结构保持映射
// readonly pick partial是同态的

/**
 * @Author: zxc
 * @Date: 2020-08-06 10:52:40
 * @func: 由映射类型进行推断
 */

// 拆包
type Proxy<T> = {
  get(): T;
  set(value: T): void;
};

type Proxyify<T> = {
  [P in keyof T]: Proxy<T[P]>;
};
function proxify<T>(obj: T): Proxyify<T> {
  const res = {} as Proxyify<T>;
  // tslint:disable-next-line:forin
  for (const key in obj) {
    res[key] = {
      get: () => obj[key],
      set: (value) => (obj[key] = value),
    };
  }
  return res;
}
let propss = {
  name: "zxc",
  age: 23,
};
let proxyprops = proxify(propss);
// console.log(proxyprops)
// proxyprops.name.get()
// proxyprops.name.set('zxc1')
// console.log(proxyprops.name.get())

function unProxify<T>(t: Proxyify<T>): T {
  const res = {} as T;
  // tslint:disable-next-line:forin
  for (const i in t) {
    res[i] = t[i].get();
  }
  return res;
}
let originProxy = unProxify(proxyprops);
console.log(originProxy);

// unknown
/***
 * 1.任何类型都可以赋值给unknown类型
 */

let values1: unknown;
values1 = "a";
values1 = 2;

/***
 * 2.如果没有类型断言或基于控制流的类型细化时，unknown不可以赋值其他类型，此时他只能赋值给unknown和any类型
 */
let values3: unknown;
// let values4:string = values3
values3 = values1;

/***
 * 3.如果没有类型断言或基于控制流的类型细化时，不能在他上面进行任何操作
 */
let values5: unknown;
// values5 += 1

/***
 * 4.unknown与任何其它类型组成的交叉类型，最后都等于其它类型
 */
type types1 = string & unknown;
type types2 = number & unknown;
type types3 = unknown & unknown;
type types4 = string[] & unknown;

/***
 * 5.unknown与任何其它类型组成的联合类型（除了any），都等于unknown类型
 */
type types5 = unknown | string;
type types6 = any | string;
type types7 = number[] | unknown;

/***
 * 6.never类型是unknow类型的子类型
 */
type types8 = never extends unknown ? true : false;

/***
 * 7.keyof unknown 等于类型 never
 */
type types9 = keyof unknown;

/***
 * 8. 只能对unknown进行等或不等操作，不能进行其它操作
 */
// tslint:disable-next-line:no-unused-expression
values1 !== values3;
// values1 + values3

/***
 * 9. unknown类型的值 不能访问他的属性、也不能作为函数调用和作为类创建实例
 */
let values6: unknown;
// values6.age
// values6()
// new values6()

/***
 * 10. 使用映射类型时如果遍历的是unknown类型，则不会映射任何属性
 */
type Types11<T> = {
  [P in keyof T]: number;
};
type type11 = Types11<any>;
type type12 = Types11<unknown>;

/**
 * @Author: zxc
 * @Date: 2020-08-06 13:29:25
 * @func: 条件类型
 */
type Types12<T> = T extends string ? string : number;
let index: Types12<"a">;

/**
 * 分布式条件类型
 */
// type TypeName<T> = T extends any ? T : never;
// type Types13 = TypeName<string | number>;

type TypeName<T> = T extends string
  ? string
  : T extends number
  ? number
  : T extends boolean
  ? boolean
  : T extends undefined
  ? undefined
  : T extends () => void
  ? () => void
  : object;

type types14 = TypeName<() => void>;
type types15 = TypeName<string[]>;
type types16 = TypeName<(() => void) | string[]>;

type Diffs<T, U> = T extends U ? never : T;
type Tests = Diffs<string | number | boolean, undefined | number>;

type Types17<T> = {
  // tslint:disable-next-line: ban-types
  [K in keyof T]: T[K] extends Function ? K : never;
}[keyof T];

interface Parets {
  id: number;
  name: string;
  subparts: Parets[];
  undatePart(newName: string): void;
}
type Testss = Types17<Parets>;

// infer关键字
type Types18<T> = T extends any[] ? T[number] : T;
type Tests2 = Types18<string[]>;
type Tests4 = Types18<string>;

type Types19<T> = T extends (infer U)[] ? U : T;
type Tests5 = Types19<string[]>;
type Tests6 = Types19<number>;

// Exclude<T,U>
type Types20 = Exclude<"A" | "B" | "C", "A">;

// Extract<T,U>
type Types21 = Extract<"a" | "b" | "c", "c">;

// NonNullable<T>
type Types22 = NonNullable<string | number | null | undefined>;


// ReturnType<T>
type Types23 = ReturnType<() => string> 
type Types24 = ReturnType<() => void>

// InstanceType<T>
class DemosCl{
  // tslint:disable-next-line:no-empty
  constructor(){}
}
type T1 = InstanceType<typeof DemosCl>
type T2 = InstanceType<any>
type T3 = InstanceType<never>
// type T4 = InstanceType<string>



interface Logger {
  time: number;
  asyncLog:(msg: string) => Promise<string>
  syncLog:(msg: string) => number;
}

type FilterTypes<T, U> = {
  [Key in keyof T]: T[Key] extends U ? Key : never
};
// type TSD = FilterTypes<Logger,Function>

type FilterKeys<T, U> = FilterTypes<T, U>[keyof T];

type SubType<T, U> = Pick<T, FilterKeys<T, U>>;
// type T11 = SubType<Logger, Function>;

// 将参数类型作为返回类型
type ArgAsReturn<T> = {
  [K in keyof T]: T[K] extends ((arg: infer U) => any) ? ((arg: U) => U): never;
}

// 我们最终得到了 Translate
// tslint:disable-next-line:ban-types
type Translate<T> = ArgAsReturn<SubType<T, Function>>

// 看看最后效果，满足要求
type Ts = Translate<Logger>

// type T0 = {
//     asyncLog: (arg: string) => string;
//     syncLog: (arg: string) => string;
// }